/*
 * @Author: 码农 2646995216@qq.com
 * @Date: 2025-03-12 01:09:12
 * @LastEditors: 码农 2646995216@qq.com
 * @LastEditTime: 2025-03-15 13:16:31
 * @FilePath: /socket_udp/udpserver.hpp
 * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
 */
#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>

using namespace std;

#define SIZE 1024

string address = "127.0.0.1";
// uint16_t mark=8888;

class UdpServer
{
public:
	UdpServer(uint16_t port, const string &ip = address)
		: _ip(ip), _port(port), _socket(-1)
	{
	}

	// 服务器初始化
	void ServerInit()
	{
		// 创建套接字，并返回网络文件描述符，并放入_socket中
		_socket = socket(AF_INET, SOCK_DGRAM, 0); // AF_INET：表示使用IPv4的网络套接字进行网络通信
		if (_socket < 0)							  // SOCK_DGRAM：表示面向用户数据报，对应了和UDP协议
		{
			cout << "socket false" << endl;
			exit(1);
		}
		cout << "socket success" << endl;
		// 将套接字绑定IP地址，端口号
		struct sockaddr_in addr;	                   // 创建网络套接字
		bzero(&addr, sizeof(addr));		               //初始化网络套接字
		addr.sin_family = AF_INET;					   // AF_INET：表示使用IPv4的网络套接字进行网络通信
		addr.sin_port = htons(_port);				   // 将端口号转化为网络字节序
		addr.sin_addr.s_addr = inet_addr(_ip.c_str()); //_ip.cstr()就是将string类型转化为const char*类型

		socklen_t len = sizeof(addr);
		// 将套接字与系统绑定
		int n = bind(_socket, (const struct sockaddr *)&addr, len);
		if (n < 0)
		{
			cout << "bind false" << endl;
			exit(2);
		}
		cout << "bind success" << endl;
	}

	// 启动服务器
	void ServerRun()
	{
		char buffer[SIZE]; // 定义一个缓冲区，用来存放客户端的数据
		while (true)
		{
			struct sockaddr_in client; // 用来存放客户端的网络套接字，里面包含ip地址，端口号
			socklen_t len = sizeof(client);
			ssize_t n = recvfrom(_socket, (void *)buffer, sizeof(buffer) - 1, 0, (struct sockaddr *)&client, &len); // 接收客户端的数据，将其放入缓冲区中，并且保存其网络套接字
			if (n > 0)
			{
				buffer[n] = '\0';
				string client_ip = inet_ntoa(client.sin_addr); // 将in_addr_t类型的ip转换为char*类型的ip
				uint16_t client_port = ntohs(client.sin_port); // 将从网络上读取的端口号转换成主机的字节序
				cout << "ip地址:" << client_ip.c_str() << "," << "端口号:" << client_port << ",client say:" << buffer << endl;
			}else{
				cout << "error";
			}
		}
	}

private:
	uint16_t _port; // 服务器端口号
	string _ip;		// 服务器ip地址
	int _socket;	// 网络文件描述符
};



